<?php

namespace app\library;

/**
 * Class Tree
 * @package app\library
 */
class Tree
{

    /**
     * 一维数据数组生成数据树
     * @param array $list 数据列表
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @param string $son 定义子数据Key
     * @return array
     */
    public static function getTreeArray($list, $id = 'id', $pid = 'pid', $son = 'sub')
    {
        list($tree, $map) = [[], []];
        foreach ($list as $item) $map[$item[$id]] = $item;
        foreach ($list as $item) if (isset($item[$pid]) && isset($map[$item[$pid]])) {
            $map[$item[$pid]][$son][] = &$map[$item[$id]];
        } else $tree[] = &$map[$item[$id]];
        unset($map);
        return $tree;
    }

    /**
     * 一维数据数组生成数据树
     * @param array $list 数据列表
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @param string $path
     * @param string $ppath
     * @return array
     */
    public static function getTreeTable($list, $id = 'id', $pid = 'pid', $path = 'path', $ppath = '')
    {
        $tree = [];
        foreach (self::getTreeArray($list, $id, $pid) as $attr) {
            $attr[$path] = "{$ppath}-{$attr[$id]}";
            $attr['sub'] = isset($attr['sub']) ? $attr['sub'] : [];
            $attr['spt'] = substr_count($ppath, '-');
            $attr['spl'] = str_repeat("　├　", $attr['spt']);
            $sub = $attr['sub'];
            unset($attr['sub']);
            $tree[] = $attr;
            if (!empty($sub)) $tree = array_merge($tree, self::getTreeTable($sub, $id, $pid, $path, $attr[$path]));
        }
        return $tree;
    }
    
    /**
     * 得到子级数组
     * @param array $list 数据列表
     * @param int $nid 节点ID
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @return array
     */
    public static function getChild($list, $nid, $id = 'id', $pid = 'pid')
    {
        $newarr = [];
        foreach ($list as $value) {
            if (!isset($value[$id])) {
                continue;
            }
            if ($value[$pid] == $nid) {
                $newarr[$value[$id]] = $value;
            }
        }
        return $newarr;
    }
    
    /**
     * 读取指定节点的所有孩子节点
     * @param array $list 数据列表
     * @param int $nid 节点ID
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @param boolean $withself 是否包含自身
     * @return array
     */
    public static function getChildren($list, $nid, $id = 'id', $pid = 'pid', $withself = false)
    {
        $newarr = [];
        foreach ($list as $value) {
            if (!isset($value[$id])) {
                continue;
            }
            if ($value[$pid] == $nid) {
                $newarr[] = $value;
                $newarr = array_merge($newarr, self::getChildren($list, $value[$id], $id, $pid));
            } elseif ($withself && $value[$id] == $nid) {
                $newarr[] = $value;
            }
        }
        return $newarr;
    }
    
    /**
     * 读取指定节点的所有孩子节点ID
     * @param array $list 数据列表
     * @param int $nid 节点ID
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @param boolean $withself 是否包含自身
     * @return array
     */
    public static function getChildrenIds($list, $nid, $id = 'id', $pid = 'pid', $withself = false)
    {
        $childrenlist = self::getChildren($list, $nid, $id, $pid, $withself);
        $childrenids = [];
        foreach ($childrenlist as $k => $v) {
            $childrenids[] = $v[$id];
        }
        return $childrenids;
    }
    
    /**
     * 得到当前位置父辈数组
     * @param array $list 数据列表
     * @param int $nid 节点ID
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @return array
     */
    public static function getParent($list, $nid, $id = 'id', $pid = 'pid')
    {
        list($parent_id, $newarr) = [0, []];
        foreach ($list as $value) {
            if (!isset($value[$id])) {
                continue;
            }
            if ($value[$id] == $nid) {
                $parent_id = $value[$pid];
                break;
            }
        }
        if ($parent_id) {
            foreach ($list as $value) {
                if ($value[$id] == $parent_id) {
                    $newarr[] = $value;
                    break;
                }
            }
        }
        return $newarr;
    }
    
    /**
     * 得到当前位置所有父辈数组
     * @param array $list 数据列表
     * @param int $nid 节点ID
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @param boolean $withself 是否包含自身
     * @return array
     */
    public static function getParents($list, $nid, $id = 'id', $pid = 'pid', $withself = false)
    {
        list($parent_id, $newarr) = [0, []];
        foreach ($list as $value) {
            if (!isset($value[$id])) {
                continue;
            }
            if ($value[$id] == $nid) {
                if ($withself) {
                    $newarr[] = $value;
                }
                $parent_id = $value[$pid];
                break;
            }
        }
        if ($parent_id) {
            $arr = self::getParents($list, $parent_id, $id, $pid, true);
            $newarr = array_merge($arr, $newarr);
        }
        return $newarr;
    }
    
    /**
     * 读取指定节点所有父类节点ID
     * @param array $list 数据列表
     * @param int $nid 节点ID
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @param boolean $withself 是否包含自身
     * @return array
     */
    public static function getParentsIds($list, $nid, $id = 'id', $pid = 'pid', $withself = false)
    {
        $parentlist = self::getParents($list, $nid, $id, $pid, $withself);
        $parentsids = [];
        foreach ($parentlist as $k => $v) {
            $parentsids[] = $v[$id];
        }
        return $parentsids;
    }
    
    /**
     * 读取指定节点数据列表生成数据树
     * @param array $list 数据列表
     * @param int $nid 节点ID
     * @param string $id ID Key
     * @param string $pid 父ID Key
     * @param boolean $withself 是否包含自身
     * @return array
     */
    public static function getTreeArrayByNode($list, $nid, $id = 'id', $pid = 'pid') 
    {
        list($n, $number, $data) = [0, 1, []];
        $childs = self::getChild($list, $nid, $id, $pid);
        if ($childs) {
            foreach ($childs as $cid => $value) {
                $data[$n] = $value;
                $sub = self::getTreeArrayByNode($list, $cid, $id, $pid);
                !empty($sub) && $data[$n]['sub'] = $sub;
                $n++;
                $number++;
            }
        }
        return $data;
    }
    
}
